import pytest
from playwright.sync_api import Page, Browser, BrowserContext
import os
from datetime import datetime
from config.config import config
import allure

# 配置基础URL
@pytest.fixture(scope="session")
def base_url():
    """
    提供测试环境的基础URL，从配置文件中读取
    """
    return config.base_url

# 全局的 Page 对象 Fixture
@pytest.fixture(scope="function")
def page(page: Page):
    """
    一个全局的 fixture，用于向测试用例提供 Playwright 的 Page 对象。
    """
    # 设置默认的超时时间，从配置文件中读取
    page.set_default_timeout(config.timeout)
    yield page
    # 由 pytest-playwright 自动管理页面关闭

# 截图 Fixture
@pytest.fixture(scope="function", autouse=True)
def screenshot_on_failure(request, page: Page):
    """
    测试失败时自动截图并附加到Allure报告的fixture
    """
    yield
    
    # 测试失败时进行截图
    if request.node.rep_call.failed if hasattr(request.node, "rep_call") else False:
        # 生成截图
        screenshot_bytes = page.screenshot()
        
        # 将截图附加到Allure报告
        allure.attach(
            screenshot_bytes,
            name=f"{request.node.name}_failure_screenshot",
            attachment_type=allure.attachment_type.PNG
        )
        
        # (可选) 同时将截图保存到本地
        # 使用配置中的截图目录，如果未配置则使用默认值
        screenshots_dir = getattr(config, 'screenshot_dir', 'reports/screenshots')
        os.makedirs(screenshots_dir, exist_ok=True)
        
        # 生成截图文件名
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        test_name = request.node.name
        screenshot_path = os.path.join(screenshots_dir, f"{test_name}_{timestamp}.png")
        
        # 保存截图
        with open(screenshot_path, "wb") as f:
            f.write(screenshot_bytes)
        print(f"测试失败截图保存在: {screenshot_path}")

# 回退到消息列表页面的 Fixture
@pytest.fixture(scope="function")
def navigate_back_to_messages(page: Page, base_url):
    """
    测试结束后回退到消息列表页面的fixture
    如果当前不在消息列表页面，会一直回退直到找到消息列表页面
    """
    # 先执行测试
    yield
    
    # 测试结束后，检查是否在消息列表页面，如果不在则回退
    max_attempts = 5  # 最大回退次数，防止无限循环
    attempts = 0
    
    while attempts < max_attempts:
        # 检查当前是否在消息列表页面
        if is_on_message_page(page):
            print("已在消息列表页面")
            break
            
        print(f"不在消息列表页面，尝试回退 (尝试 {attempts+1}/{max_attempts})")
        page.go_back()
        page.wait_for_load_state("networkidle")
        attempts += 1
        
        # 如果回退后到达消息列表页面，则退出循环
        if is_on_message_page(page):
            print("成功回退到消息列表页面")
            break
    
    # 如果回退多次后仍未到达消息列表页面，则直接导航到消息列表页面
    if not is_on_message_page(page):
        print("无法通过回退到达消息列表页面，直接导航到消息列表页面")
        page.goto(f"{base_url}/campustradingwall_war_exploded/user/messages")
        page.wait_for_load_state("networkidle")

def is_on_message_page(page: Page) -> bool:
    """
    检查当前是否在消息列表页面
    
    :param page: Playwright的Page对象
    :return: 如果在消息列表页面返回True，否则返回False
    """
    try:
        # 检查URL是否包含消息列表的路径
        current_url = page.url
        if "/user/messages" in current_url:
            return True
            
        # 检查页面上是否有消息列表的特征元素
        # 这里假设消息列表页面有一个特定的标题或元素
        # 根据实际页面结构调整选择器
        message_title_visible = page.is_visible("text='我的消息'") or page.is_visible("h1:has-text('消息列表')")
        message_list_visible = page.is_visible(".message-list") or page.is_visible(".messages-container")
        
        return message_title_visible or message_list_visible
    except:
        return False

# 持久化登录状态的 Fixture
@pytest.fixture(scope="function")
def authenticated_page(browser: Browser, base_url):
    """
    提供一个已经登录的页面对象
    """
    # 创建一个新的浏览器上下文
    context = browser.new_context(storage_state=None)
    page = context.new_page()
    page.set_default_timeout(10000)
    
    # 执行登录操作
    page.goto(f"{base_url}/campustradingwall_war_exploded/login.jsp")
    page.fill("#username", "李沂杭")
    page.fill("#password", "123456")
    page.click("button.btn")
    
    # 等待登录完成
    page.wait_for_selector("header .header-user-actions span")
    
    yield page
    
    # 清理
    context.close()

# 移动设备模拟 Fixture
@pytest.fixture(scope="function")
def mobile_page(browser: Browser):
    """
    提供一个模拟移动设备的页面对象
    """
    # 创建一个模拟iPhone的上下文
    iphone_11 = {
        'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1',
        'viewport': {
            'width': 375,
            'height': 812
        },
        'deviceScaleFactor': 3,
        'isMobile': True,
        'hasTouch': True
    }
    
    context = browser.new_context(**iphone_11)
    page = context.new_page()
    page.set_default_timeout(10000)
    
    yield page
    
    # 清理
    context.close()

# 记录测试结果的钩子
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
    outcome = yield
    rep = outcome.get_result()
    setattr(item, f"rep_{rep.when}", rep)